package com.modern.devtools.service;

import com.modern.devtools.infrastructure.SSHConnectionPool;
import com.modern.devtools.interfaces.CommandExecutor;
import com.modern.devtools.model.Server;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * Server Service - manages server configurations and SSH connections
 * This is a core service that other services depend on for remote command execution
 */
@Service
public class ServerService {

    private final ObservableList<Server> servers = FXCollections.observableArrayList();
    private final ConcurrentMap<String, Server> serverMap = new ConcurrentHashMap<>();

    @Autowired
    private SSHConnectionPool sshConnectionPool;

    /**
     * Adds a new server to the management system
     * @param server The server to add
     */
    public void addServer(Server server) {
        if (!serverMap.containsKey(server.getId())) {
            servers.add(server);
            serverMap.put(server.getId(), server);
        }
    }

    /**
     * Updates an existing server
     * @param server The server with updated information
     */
    public void updateServer(Server server) {
        Server existingServer = serverMap.get(server.getId());
        if (existingServer != null) {
            // Remove the old entry
            servers.remove(existingServer);
            // Update the map
            serverMap.put(server.getId(), server);
            // Add the updated server to the list
            servers.add(server);
        }
    }

    /**
     * Removes a server from the management system
     * @param serverId The ID of the server to remove
     */
    public void removeServer(String serverId) {
        Server server = serverMap.remove(serverId);
        if (server != null) {
            servers.remove(server);
            // Disconnect if connected
            sshConnectionPool.disconnect(server);
        }
    }

    /**
     * Gets a server by its ID
     * @param serverId The ID of the server to retrieve
     * @return Optional containing the server if found
     */
    public Optional<Server> getServerById(String serverId) {
        return Optional.ofNullable(serverMap.get(serverId));
    }

    /**
     * Gets all servers
     * @return ObservableList of all servers
     */
    public ObservableList<Server> getAllServers() {
        return FXCollections.unmodifiableObservableList(servers);
    }

    /**
     * Tests connection to a server
     * @param serverId The ID of the server to test
     * @return true if connection is successful, false otherwise
     */
    public boolean testConnection(String serverId) {
        Optional<Server> serverOpt = getServerById(serverId);
        if (serverOpt.isPresent()) {
            Server server = serverOpt.get();
            try {
                // Connect to the server
                sshConnectionPool.connect(server);

                // Execute a simple command to test connectivity
                CommandExecutor.ExecutionResult result = sshConnectionPool.executeCommand(server, "echo 'Connection test successful'");

                // Disconnect
                sshConnectionPool.disconnect(server);

                return result.isSuccess();
            } catch (Exception e) {
                return false;
            }
        }
        return false;
    }

    /**
     * Executes a command on a specific server
     * @param serverId The ID of the server to execute on
     * @param command The command to execute
     * @return Execution result
     */
    public CommandExecutor.ExecutionResult executeCommand(String serverId, String command) {
        Optional<Server> serverOpt = getServerById(serverId);
        if (serverOpt.isPresent()) {
            return sshConnectionPool.executeCommand(serverOpt.get(), command);
        } else {
            throw new IllegalArgumentException("Server with ID " + serverId + " not found");
        }
    }

    /**
     * Gets the number of servers in the system
     * @return Number of servers
     */
    public int getServerCount() {
        return servers.size();
    }

    /**
     * Gets the number of connected servers
     * @return Number of connected servers
     */
    public int getConnectedServerCount() {
        return (int) servers.stream()
                .filter(server -> sshConnectionPool.isConnected(server))
                .count();
    }
}
